feat(expression): cast numeric literals to decimal type#805
Open
huan233usc wants to merge 7 commits into
Open
Conversation
huan233usc
marked this pull request as ready for review
July 3, 2026 21:18
wgtmac
reviewed
Jul 11, 2026
wgtmac
reviewed
Jul 11, 2026
huan233usc
force-pushed
the
feat/default-values-numeric-decimal-cast
branch
from
July 12, 2026 21:20
e5e3610 to
09a45b6
Compare
There was a problem hiding this comment.
Pull request overview
This PR extends Literal::CastTo to support casting numeric literals (int, long, float, double) into a decimal target type, aligning C++ literal-cast behavior with Java’s numeric-to-decimal default handling. It adds new decimal-cast logic for integer and real sources and introduces targeted unit tests to validate scaling, rounding, and rejection behavior.
Changes:
- Add integer→decimal and real→decimal cast paths in
LiteralCaster, including HALF_UP rounding behavior. - Add
RescaleHalfUphelper to support HALF_UP rounding (including negative target scales) while avoiding unsafe power-of-ten indexing in some cases. - Add new tests covering integer/real decimal casts, scale handling, rounding behavior, and error cases.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/iceberg/expression/literal.cc | Adds numeric→decimal casting logic and a HALF_UP rescaling helper used by Literal::CastTo. |
| src/iceberg/test/literal_test.cc | Adds unit tests validating integer/real casts to decimal, rounding rules, and error handling. |
Validate target scale bounds, avoid int128 overflow in HALF_UP by comparing against divisor/2, and use std::to_chars for shortest round-trip conversion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Add casting of numeric literals (
int,long,float,double) to a decimal target type inLiteral::CastTo, so a numeric value can be used as a default for a decimal column.Previously
CastFromInt/CastFromLong/CastFromFloat/CastFromDoublehad nokDecimalcase and fell through toNotSupported, so a default likeLiteral::Int(12)orLiteral::Double(9.99)for adecimal(9, 2)column was rejected. Java allows these (IntegerLiteral.to,DoubleLiteral.to, etc. scale the value to the target scale), so this brings the C++ literal cast layer to parity for numeric sources.How
CastIntegerToDecimalscales the integer (scale 0) up to the target scale viaDecimal::Rescale(0, scale), then verifies the result fits the target precision (FitsInPrecision). Example:12→decimal(9,2)yields unscaled1200(12.00).CastRealToDecimalparses the value's shortest round-tripping decimal representation (matching Java'sBigDecimal.valueOf(double)viaDouble.toString), then rounds to the target scale with HALF_UP rounding (round half away from zero, as Java does —2.5→3,-2.5→-3), and checks precision. Non-finite values are rejected.DecimalTypedoes not bound its scale on construction, sodecimal(9, 40)would otherwise read past the table).Scope
Follow-up split out from the v3 default-value work (see the
CastDefaultToTypediscussion on #793). It only extends the sharedLiteral::CastTolayer for numeric sources.Testing
LiteralTest.IntegerCastToDecimal(int/long scaling, out-of-precision rejection, out-of-range scale rejection) andLiteralTest.RealCastToDecimal(float/double scaling, HALF_UP rounding incl. negative, round-down, out-of-precision and non-finite rejection), all verified fail-without / pass-with. Fullexpression_testpasses (495 tests).